{
  Envs(values)::
    [
      {
        name: name,
        value: values[name],
      }
      for name in std.objectFields(values)
    ],
  ServicePorts(ports)::
    [
      {
        name: 'tcp-' + std.toString(port),
        protocol: 'TCP',
        targetPort: port,
        port: port,
      }
      for port in ports
    ],
  ContainerPorts(ports)::
    [
      {
        name: 'tcp-' + std.toString(port),
        protocol: 'TCP',
        containerPort: port,
      }
      for port in ports
    ],

  Service(name, _values)::
    local values = std.mergePatch({
      labels: {},
      annotations: {},
      type: 'ClusterIP',
      selector: {},
      ports: {
        tcp: [],
        udp: [],
        http: [],
      },
      overrides: {
        spec: {},
      },
    }, _values);
    {
      apiVersion: 'v1',
      kind: 'Service',
      metadata: {
        name: name,
        [if std.length(values.labels) != 0 then 'labels']: values.labels,
        [if std.length(values.annotations) != 0 then 'annotations']: values.annotations,
      },
      spec: std.mergePatch({
        type: values.type,
        selector: (
          if std.length(values.selector) == 0
          then
            {
              app: name,
            }
          else
            values.selector
        ),
        ports: [
          {
            name: 'tcp-' + std.toString(port),
            protocol: 'TCP',
            targetPort: port,
            port: port,
          }
          for port in values.ports.tcp

        ] + [
          {
            name: 'udp-' + std.toString(port),
            protocol: 'UDP',
            targetPort: port,
            port: port,
          }
          for port in values.ports.udp
        ] + [
          {
            name: 'http-' + std.toString(port),
            protocol: 'TCP',
            targetPort: port,
            port: port,
          }
          for port in values.ports.http
        ],
      }, values.overrides.spec),
    },

  VolumeClaimTemplate(name, _values)::
    local values = std.mergePatch({
      labels: {},
      annotations: {},
      accessModes: ['ReadWriteOnce'],
      class: 'local-path',
      capacity: '10Gi',
    }, _values);

    {
      metadata: {
        name: name,
        labels: values.labels,
        annotations: values.annotations,
      },
      spec: {
        accessModes: values.accessModes,
        storageClassName: values.class,
        resources: {
          requests: {
            storage: values.capacity,
          },
        },
      },
    },

  PersistentVolumeClaim(name, _values)::
    self.VolumeClaimTemplate(name, _values) +
    {
      apiVersion: 'v1',
      kind: 'PersistentVolumeClaim',
    },

  StatefulSet(name, _values)::
    local values = std.mergePatch({
      image: '',
      labels: {},
      annotations: {},
      podLabels: {},
      podAnnotations: {},
      env: [],
      command: null,
      args: null,
      volumes: [],
      volumeMounts: [],
      resources: {},
      volumeClaimTemplates: [],
      overrides: {
        spec: {
        },
        container: {},
        containers: [],
      },
    }, _values);
    {
      apiVersion: 'apps/v1',
      kind: 'StatefulSet',
      metadata: {
        name: name,
        [if std.length(values.labels) != 0 then 'labels']: values.labels,
        [if std.length(values.annotations) != 0 then 'annotations']: values.annotations,
      },
      spec: std.mergePatch(
        {
          serviceName: name,
          selector: {
            matchLabels: {
              app: name,
            },
          },
          [if std.length(values.volumeClaimTemplates) != 0 then 'volumeClaimTemplates']: values.volumeClaimTemplates,
          template: {
            metadata: {
              labels: values.podLabels {
                app: name,
              },
              [if std.length(values.podAnnotations) != 0 then 'annotations']: values.podAnnotations,
            },
            spec: {
              containers: [
                std.mergePatch({
                  name: name,
                  image: values.image,
                  imagePullPolicy: 'IfNotPresent',
                  [if values.command != null then 'command']: values.command,
                  [if values.args != null then 'args']: values.args,
                  env: values.env,
                  resources: values.resources,
                  volumeMounts: values.volumeMounts,
                }, values.overrides.container),
              ] + values.overrides.containers,
              volumes: values.volumes,
            },
          },
        },
        values.overrides.spec
      ),
    },

  Deployment(name, _values)::
    local values = std.mergePatch({
      image: '',
      labels: {},
      annotations: {},
      podLabels: {},
      podAnnotations: {},
      env: [],
      command: null,
      args: null,
      volumes: [],
      volumeMounts: [],
      resources: {},
      overrides: {
        spec: {
        },
        container: {},
        containers: [],
      },
    }, _values);
    {
      apiVersion: 'apps/v1',
      kind: 'Deployment',
      metadata: {
        name: name,
        [if std.length(values.labels) != 0 then 'labels']: values.labels,
        [if std.length(values.annotations) != 0 then 'annotations']: values.annotations,
      },
      spec: std.mergePatch(
        {
          selector: {
            matchLabels: {
              app: name,
            },
          },
          template: {
            metadata: {
              labels: values.podLabels {
                app: name,
              },
              [if std.length(values.podAnnotations) != 0 then 'annotations']: values.podAnnotations,
            },
            spec: {
              containers: [
                std.mergePatch({
                  name: name,
                  image: values.image,
                  imagePullPolicy: 'IfNotPresent',
                  [if values.command != null then 'command']: values.command,
                  [if values.args != null then 'args']: values.args,
                  env: values.env,
                  resources: values.resources,
                  volumeMounts: values.volumeMounts,
                }, values.overrides.container),
              ] + values.overrides.containers,
              volumes: values.volumes,
            },
          },
        },
        values.overrides.spec
      ),
    },
}
